home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / role / ZIP_1_0.lha / src / text.c < prev    next >
C/C++ Source or Header  |  1992-10-13  |  18KB  |  794 lines

  1. /*
  2.  * text.c
  3.  *
  4.  * Text manipulation routines
  5.  *
  6.  * Mark Howell 28-Jul-1992 V1.0
  7.  *
  8.  */
  9.  
  10. #include "ztypes.h"
  11.  
  12. static const char *lookup_table[3] = {
  13.     "abcdefghijklmnopqrstuvwxyz",
  14.     "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  15.     "\n 0123456789.,!?_#'\"/\\-:()"
  16. };
  17. static int saved_format_mode = ON;
  18. static int line_pos = 0;
  19. static int story_redirect = OFF;
  20. static int story_buffer = 0;
  21. static int story_pos = 0;
  22. static int story_count = 0;
  23.  
  24. /*
  25.  * decode_text
  26.  *
  27.  * Convert encoded text to ASCII. Text is encoded by squeezing each character
  28.  * into 5 bits. 3 x 5 bit encoded characters can fit in one word with a spare
  29.  * bit left over. The spare bit is used to signal to end of a string. The 5 bit
  30.  * encoded characters can either be actual character codes or prefix codes that
  31.  * modifier the following code.
  32.  *
  33.  */
  34.  
  35. #ifdef __STDC__
  36. void decode_text (unsigned long *address)
  37. #else
  38. void decode_text (address)
  39. unsigned long *address;
  40. #endif
  41. {
  42.     int i, synonym_flag = 0, ascii_flag = 0;
  43.     short data, code, sindex = 0;
  44.     short prefix = 0, saved_prefix = 0;
  45.     unsigned long addr;
  46.  
  47.     /* Loop until high bit set in word */
  48.  
  49.     do {
  50.  
  51.         /* Load a word */
  52.  
  53.         data = read_data_word (address);
  54.  
  55.         /* Parse each 5 bit code in a word */
  56.  
  57.         for (i = 10; i >= 0; i -= 5) {
  58.             code = (data >> i) & 0x1f;
  59.  
  60.             /* If the synonym flag is set then the code specifies a longer
  61.                string which needs to be decoded to get the text */
  62.  
  63.             if (synonym_flag) {
  64.                 synonym_flag = 0;
  65.                 addr = (unsigned long) get_word (h_synonyms_offset + sindex + (code * 2)) * 2;
  66.                 decode_text (&addr);
  67.                 prefix = saved_prefix;
  68.             } else {
  69.  
  70.                 /* If the ascii flag is set then we have an ascii character that
  71.                    is composed of 3 bits from the previous code and 5 bits from
  72.                    the current code to make an 8 bit character */
  73.  
  74.                 if (ascii_flag || prefix == 3) {
  75.                     if (ascii_flag) {
  76.                         ascii_flag = 0;
  77.                         write_char ((char) (((prefix & 3) << 5) | code));
  78.                         prefix = saved_prefix;
  79.                     } else {
  80.                         ascii_flag = 1;
  81.                         prefix = code;
  82.                     }
  83.                 } else {
  84.                     if (code >= 6) {
  85.                         if (prefix == 2 && code <= 7) {
  86.                             if (code != 7)
  87.                                 prefix++;
  88.                             else {
  89.  
  90.                                 /* Output a newline */
  91.  
  92.                                 flush_buffer (TRUE);
  93.                                 prefix = saved_prefix;
  94.                             }
  95.                         } else {
  96.  
  97.                             /* Convert encoded character to ascii */
  98.  
  99.                             write_char (lookup_table[prefix][code - 6]);
  100.                             prefix = saved_prefix;
  101.                         }
  102.                     } else {
  103.                         if (code == 0) {
  104.  
  105.                             /* Output a space */
  106.  
  107.                             write_char (' ');
  108.                             prefix = saved_prefix;
  109.                         } else {
  110.                             if (code <= 3) {
  111.  
  112.                                 /* Calculate a synonym index */
  113.  
  114.                                 synonym_flag = 1;
  115.                                 sindex = (code - 1) * 64;
  116.                             } else {
  117.                                 code -= 3;
  118.                                 if (prefix == 0)
  119.                                     prefix = code;
  120.                                 else {
  121.                                     if (code != prefix)
  122.                                         prefix = 0;
  123.                                     saved_prefix = prefix;
  124.                                 }
  125.                             }
  126.                         }   
  127.                     }
  128.                 }
  129.             }
  130.         }
  131.     } while (data >= 0);
  132.  
  133. }/* decode_text */
  134.  
  135. /*
  136.  * character_to_prefix
  137.  *
  138.  * Convert a character to a prefix type for encoding.
  139.  *
  140.  */
  141.  
  142. #ifdef __STDC__
  143. static char character_to_prefix (char c)
  144. #else
  145. static char character_to_prefix (c)
  146. char c;
  147. #endif
  148. {
  149.     int i;
  150.  
  151.     for (i = 0; i < 3; i++)
  152.         if (strchr (lookup_table[i], c) != NULL)
  153.             return ((char) i);
  154.  
  155.     return (2);
  156.  
  157. }/* character_to_prefix */
  158.  
  159. /*
  160.  * character_to_code
  161.  *
  162.  * Convert a character to an encoded character.
  163.  *
  164.  */
  165.  
  166. #ifdef __STDC__
  167. static char character_to_code (char c)
  168. #else
  169. static char character_to_code (c)
  170. char c;
  171. #endif
  172. {
  173.     int i;
  174.     const char *cp;
  175.  
  176.     for (i = 0; i < 3; i++)
  177.         if ((cp = strchr (lookup_table[i], c)) != NULL)
  178.             return ((char) ((cp - lookup_table[i]) + 6));
  179.  
  180.     return (0);
  181.  
  182. }/* character_to_code */
  183.  
  184. /*
  185.  * encode_text
  186.  *
  187.  * Pack a string into upto 9 codes or 3 words.
  188.  *
  189.  */
  190.  
  191. #ifdef __STDC__
  192. void encode_text (int len, const char *s, short *buffer)
  193. #else
  194. void encode_text (len, s, buffer)
  195. int len;
  196. const char *s;
  197. short *buffer;
  198. #endif
  199. {
  200.     int i;
  201.     char code, codes[9];
  202.  
  203.     for (i = 9; i; s++) {
  204.         if (len-- > 0) {
  205.  
  206.             /* Calculate prefix for this character */
  207.  
  208.             code = character_to_prefix (*s);
  209.  
  210.             /* Store prefix + 3 if enough room and prefix is non zero */
  211.  
  212.             if (i && code)
  213.                 codes[--i] = code + (char) 3;
  214.  
  215.             /* Calculate code for this character */
  216.  
  217.             code = character_to_code (*s);
  218.  
  219.             /* Store code + 6 if enough room and code is non zero */
  220.  
  221.             if (i && code)
  222.                 codes[--i] = code;
  223.             else {
  224.  
  225.                 /* Store and ascii character as prefix (6) + high 3 bits + low 5 bits */
  226.  
  227.                 if (i)
  228.                     codes[--i] = 6;
  229.                 if (i)
  230.                     codes[--i] = (char) (*s >> 5) & (char) 0x07;
  231.                 if (i)
  232.                     codes[--i] = *s & (char) 0x1f;
  233.             }
  234.         } else
  235.  
  236.             /* Fill remaining space with code 5 */
  237.  
  238.             codes[--i] = 5;
  239.     }
  240.  
  241.     /* Pack codes into buffer */
  242.  
  243.     buffer[0] = ((short) codes[8] << 10) | ((short) codes[7] << 5) | (short) codes[6];
  244.     buffer[1] = ((short) codes[5] << 10) | ((short) codes[4] << 5) | (short) codes[3];
  245.     buffer[2] = ((short) codes[2] << 10) | ((short) codes[1] << 5) | (short) codes[0];
  246.  
  247.     /* Set end of string terminator bit */
  248.  
  249.     if (h_type == V3)
  250.         buffer[1] |= 0x8000;
  251.     else
  252.         buffer[2] |= 0x8000;
  253.  
  254. }/* encode_text */
  255.  
  256. /*
  257.  * write_char
  258.  *
  259.  * High level character output routine. The write_char routine is slightly
  260.  * complicated by the fact that the output can be limited by a fixed character
  261.  * count, as well as, filling up the buffer.
  262.  *
  263.  */
  264.  
  265. #ifdef __STDC__
  266. void write_char (char c)
  267. #else
  268. void write_char (c)
  269. char c;
  270. #endif
  271. {
  272.     char *cp;
  273.     int cc;
  274.  
  275.     /* Only do if text formatting is turned on */
  276.  
  277.     if (format_mode == ON) {
  278.  
  279.         /* Put the character into the buffer and count it */
  280.  
  281.         line[line_pos++] = c;
  282.         char_count--;
  283.  
  284.         /* Check to see if we have reached the right margin or exhausted our
  285.            buffer space */
  286.  
  287.         if (fit_line (line, line_pos, screen_cols - RIGHT_MARGIN) == 0 || char_count == 0) {
  288.  
  289.             /* Null terminate the line */
  290.  
  291.             line[line_pos] = '\0';
  292.  
  293.             /* Find the last space character */
  294.  
  295.             cp = strrchr (line, ' ');
  296.  
  297.             /* If no space or space at the beginning of the line just output the
  298.                whole line */
  299.  
  300.             if (cp == NULL || cp == line) {
  301.  
  302.                 /* If character count exhausted then just output the line,
  303.                    otherwise preserve the character count */
  304.  
  305.                 if (char_count == 0) {
  306.                     line[0] = '\0';
  307.                     flush_buffer (TRUE);
  308.                 } else {
  309.                     cc = char_count;
  310.                     flush_buffer (TRUE);
  311.                     char_count = cc;
  312.                 }
  313.  
  314.                 /* Don't bother printing a space at the start of the line */
  315.  
  316.                 if (c == ' ')
  317.                     return;
  318.             } else {
  319.  
  320.                 /* Output up to the space and then put the remainder of the
  321.                    line at the beginning of the buffer */
  322.  
  323.                 *cp++ = '\0';
  324.                 cc = &line[line_pos] - cp;
  325.                 flush_buffer (TRUE);
  326.                 line_pos = cc;
  327.                 memmove (line, cp, line_pos);
  328.                 char_count = (screen_cols - RIGHT_MARGIN) - line_pos;
  329.             }
  330.         }
  331.     } else if (story_redirect == ON) {
  332.  
  333.         /* If redirect is on then write the character to the status line for V3
  334.            games or into the writeable data area for V4+ games */
  335.  
  336.         if (h_type == V3)
  337.             status_line[status_pos++] = c;
  338.         else {
  339.             set_byte (story_pos++, c);
  340.             story_count++;
  341.         }
  342.     } else
  343.  
  344.         /* No formatting or output redirection, so just output the character */
  345.  
  346.         output_char (c);
  347.  
  348. }/* write_char */
  349.  
  350. /*
  351.  * set_video_attribute
  352.  *
  353.  * Set a video attribute. Write the video mode, from 0 to 4, incremented.
  354.  * This is so the output routines don't confuse video attribute 0 as the
  355.  * end of the string.
  356.  *
  357.  */
  358.  
  359. #ifdef __STDC__
  360. void set_video_attribute (zword_t mode)
  361. #else
  362. void set_video_attribute (mode)
  363. zword_t mode;
  364. #endif
  365. {
  366.  
  367.     write_char ((char) ++mode);
  368.  
  369. }/* set_video_attribute */
  370.  
  371. /*
  372.  * write_string
  373.  *
  374.  * Output a string
  375.  *
  376.  */
  377.  
  378. #ifdef __STDC__
  379. void write_string (const char *s)
  380. #else
  381. void write_string (s)
  382. const char *s;
  383. #endif
  384. {
  385.  
  386.     while (*s)
  387.         write_char (*s++);
  388.  
  389. }/* write_string */
  390.  
  391. /*
  392.  * flush_buffer
  393.  *
  394.  * Send output buffer to the screen.
  395.  *
  396.  */
  397.  
  398. #ifdef __STDC__
  399. void flush_buffer (int flag)
  400. #else
  401. void flush_buffer (flag)
  402. int flag;
  403. #endif
  404. {
  405.  
  406.     /* Terminate the line */
  407.  
  408.     line[line_pos] = '\0';
  409.  
  410.     /* If flag is set then output followed by a new line */
  411.  
  412.     if (flag == TRUE)
  413.         output_stringnl (line);
  414.     else
  415.         output_string (line);
  416.  
  417.     /* Reset the buffer pointer and character count */
  418.  
  419.     line_pos = 0;
  420.     char_count = screen_cols - RIGHT_MARGIN;
  421.  
  422. }/* flush_buffer */
  423.  
  424. /*
  425.  * set_format_mode
  426.  *
  427.  * Set the format mode flag. Formatting disables writing into the output buffer.
  428.  *
  429.  */
  430.  
  431. #ifdef __STDC__
  432. void set_format_mode (zword_t flag)
  433. #else
  434. void set_format_mode (flag)
  435. zword_t flag;
  436. #endif
  437. {
  438.  
  439.     /* If flag is set then turn on formatting */
  440.  
  441.     if (flag)
  442.         format_mode = ON;
  443.     else {
  444.  
  445.         /* If the flag is clear then turn off formatting and output the current
  446.            line buffer without resetting the character count */
  447.  
  448.         format_mode = OFF;
  449.         line[line_pos] = '\0';
  450.         output_string (line);
  451.         line_pos = 0;
  452.     }
  453.  
  454. }/* set_format_mode */
  455.  
  456. /*
  457.  * set_print_modes
  458.  *
  459.  * Set various printing modes. These can be: disabling output, scripting and
  460.  * redirecting output. Redirection is peculiar. I use it to format the status
  461.  * line for V3 games, otherwise it wasn't used. V4 games format the status line
  462.  * themselves in an internal buffer in the writeable data area. To use the normal
  463.  * text decoding routines they have to redirect output to the writeable data
  464.  * area. This is done by passing in a buffer pointer. The first word of the
  465.  * buffer will receive the number of characters written since the output was
  466.  * redirected. The remainder of the buffer will contain the redirected text.
  467.  *
  468.  */
  469.  
  470. #ifdef __STDC__
  471. void set_print_modes (zword_t type, zword_t option)
  472. #else
  473. void set_print_modes (type, option)
  474. zword_t type;
  475. zword_t option;
  476. #endif
  477. {
  478.  
  479.     if ((short) type == 1) {
  480.  
  481.         /* Turn on text output */
  482.  
  483.         output_enable = ON;
  484.     } else if ((short) type == 2) {
  485.  
  486.         /* Turn on scripting */
  487.  
  488.         if ((get_word (H_FLAGS) & SCRIPTING_FLAG) == OFF)
  489.             open_script ();
  490.         set_word (H_FLAGS, SCRIPTING_FLAG);
  491.     } else if ((short) type == 3) {
  492.  
  493.         /* Redirect text output */
  494.  
  495.         /* Disable text formatting during redirection */
  496.  
  497.         saved_format_mode = format_mode;
  498.         format_mode = OFF;
  499.  
  500.         /* Enable text redirection */
  501.  
  502.         story_redirect = ON;
  503.  
  504.         /* Set up the redirection pointers */
  505.  
  506.         if (h_type == V3)
  507.             status_pos = 0;
  508.         else {
  509.             story_count = 0;
  510.             story_buffer = option;
  511.             story_pos = option + 2;
  512.         }
  513.     } else if ((short) type == -1) {
  514.  
  515.         /* Turn off text output */
  516.  
  517.         output_enable = OFF;
  518.     } else if ((short) type == -2) {
  519.  
  520.         /* Turn off scripting */
  521.  
  522.         if ((get_word (H_FLAGS) & SCRIPTING_FLAG) == ON)
  523.             close_script ();
  524.         set_word (H_FLAGS, get_word (H_FLAGS) & (~SCRIPTING_FLAG));
  525.     } else if ((short) type == -3) {
  526.  
  527.         /* Cancel text output redirection */
  528.  
  529.         if (story_redirect == ON) {
  530.  
  531.             /* Restore the format mode and turn off redirection */
  532.  
  533.             format_mode = saved_format_mode;
  534.             story_redirect = OFF;
  535.  
  536.             /* Terminate the redirection buffer and store the count of character
  537.                in the buffer into the first word of the buffer */
  538.  
  539.             if (h_type != V3) {
  540.                 set_word (story_buffer, story_count);
  541.                 set_byte (story_pos, '\0');
  542.             }
  543.         }
  544.     }
  545.  
  546. }/* set_print_modes */
  547.  
  548. /*
  549.  * print_character
  550.  *
  551.  * Write a character.
  552.  *
  553.  */
  554.  
  555. #ifdef __STDC__
  556. void print_character (zword_t c)
  557. #else
  558. void print_character (c)
  559. zword_t c;
  560. #endif
  561. {
  562.  
  563.     write_char ((char) c);
  564.  
  565. }/* print_character */
  566.  
  567. /*
  568.  * print_number
  569.  *
  570.  * Write a signed number.
  571.  *
  572.  */
  573.  
  574. #ifdef __STDC__
  575. void print_number (zword_t num)
  576. #else
  577. void print_number (num)
  578. zword_t num;
  579. #endif
  580. {
  581.     int i, count;
  582.     char buffer[10];
  583.  
  584.     i = (short) num;
  585.     sprintf (buffer, "%d", i);
  586.     count = strlen (buffer);
  587.     for (i = 0; i < count; i++)
  588.         write_char (buffer[i]);
  589.  
  590. }/* print_number */
  591.  
  592. /*
  593.  * print_address
  594.  *
  595.  * Print using a packed address. Packed addresses are used to save space and
  596.  * reference addresses outside of the data region.
  597.  *
  598.  */
  599.  
  600. #ifdef __STDC__
  601. void print_address (zword_t packed_address)
  602. #else
  603. void print_address (packed_address)
  604. zword_t packed_address;
  605. #endif
  606. {
  607.     unsigned long address;
  608.  
  609.     /* Convert packed address to real address */
  610.  
  611.     address = (unsigned long) packed_address * story_scaler;
  612.  
  613.     /* Decode and output text at address */
  614.  
  615.     decode_text (&address);
  616.  
  617. }/* print_address */
  618.  
  619. /*
  620.  * print_offset
  621.  *
  622.  * Print using a real address. Real addresses are just offsets into the
  623.  * data region.
  624.  *
  625.  */
  626.  
  627. #ifdef __STDC__
  628. void print_offset (zword_t offset)
  629. #else
  630. void print_offset (offset)
  631. zword_t offset;
  632. #endif
  633. {
  634.     unsigned long address;
  635.  
  636.     address = offset;
  637.  
  638.     /* Decode and output text at address */
  639.  
  640.     decode_text (&address);
  641.  
  642. }/* print_offset */
  643.  
  644. /*
  645.  * print_object
  646.  *
  647.  * Print an object description. Object descriptions are stored as ASCIC
  648.  * strings at the front of the property list for the object.
  649.  *
  650.  */
  651.  
  652. #ifdef __STDC__
  653. void print_object (zword_t obj)
  654. #else
  655. void print_object (obj)
  656. zword_t obj;
  657. #endif
  658. {
  659.     zword_t offset;
  660.     unsigned long address;
  661.  
  662.     /* Calculate address of property list */
  663.  
  664.     offset = get_object_address (obj);
  665.     offset += (h_type == V3) ? O3_PROPERTY_OFFSET : O4_PROPERTY_OFFSET;
  666.  
  667.     /* Read the property list address and skip the count byte */
  668.  
  669.     address = (unsigned long) get_word (offset) + 1;
  670.  
  671.     /* Decode and output text at address */
  672.  
  673.     decode_text (&address);
  674.  
  675. }/* print_object */
  676.  
  677. /*
  678.  * print_literal
  679.  *
  680.  * Print the string embedded in the instruction stream at this point. All
  681.  * strings that do not need to be referenced by address are embedded in the
  682.  * instruction stream. All strings that can be refered to by address are placed
  683.  * at the end of the code region and referenced by packed address.
  684.  *
  685.  */
  686.  
  687. #ifdef __STDC__
  688. void print_literal (void)
  689. #else
  690. void print_literal ()
  691. #endif
  692. {
  693.  
  694.     /* Decode and output text at PC */
  695.  
  696.     decode_text (&pc);
  697.  
  698. }/* print_literal */
  699.  
  700. /*
  701.  * println_return
  702.  *
  703.  * Print a string embedded in the instruction stream as with print_literal,
  704.  * except flush the output buffer and write a new line. After this return from
  705.  * the current subroutine with a status of true.
  706.  *
  707.  */
  708.  
  709. #ifdef __STDC__
  710. void println_return (void)
  711. #else
  712. void println_return ()
  713. #endif
  714. {
  715.  
  716.     print_literal ();
  717.     new_line ();
  718.     ret (TRUE);
  719.  
  720. }/* println_return */
  721.  
  722. /*
  723.  * new_line
  724.  *
  725.  * Simply flush the current contents of the output buffer followed by a new
  726.  * line.
  727.  *
  728.  */
  729.  
  730. #ifdef __STDC__
  731. void new_line (void)
  732. #else
  733. void new_line ()
  734. #endif
  735. {
  736.  
  737.     flush_buffer (TRUE);
  738.  
  739. }/* new_line */
  740.  
  741. /*
  742.  * print_time
  743.  *
  744.  * Print the time as HH:MM [am|pm]. This is a bit language dependent and can
  745.  * quite easily be changed. If you change the size of the time string output
  746.  * then adjust the status line position in display_status_line.
  747.  *
  748.  */
  749.  
  750. #ifdef __STDC__
  751. void print_time (int hours, int minutes)
  752. #else
  753. void print_time (hours, minutes)
  754. int hours;
  755. int minutes;
  756. #endif
  757. {
  758.     int pm_indicator;
  759.  
  760.     /* Remember if time is pm */
  761.  
  762.     pm_indicator = (hours < 12) ? OFF : ON;
  763.  
  764.     /* Convert 24 hour clock to 12 hour clock */
  765.  
  766.     hours %= 12;
  767.     if (hours == 0)
  768.         hours = 12;
  769.  
  770.     /* Write hour right justified */
  771.  
  772.     if (hours < 10)
  773.         write_char (' ');
  774.     print_number (hours);
  775.  
  776.     /* Write hours/minutes separator */
  777.  
  778.     write_char (':');
  779.  
  780.     /* Write minutes zero filled */
  781.  
  782.     if (minutes < 10)
  783.         write_char ('0');
  784.     print_number (minutes);
  785.  
  786.     /* Write the am or pm string */
  787.  
  788.     if (pm_indicator == ON)
  789.         write_string (" pm");
  790.     else
  791.         write_string (" am");
  792.  
  793. }/* print_time */
  794.